import re

from PySide6.QtCore import QThread, Signal

import os
import win32api
import win32event
import win32com.client
import serial.tools.list_ports
from PySide6.QtWidgets import QApplication
from win10toast import ToastNotifier

class ScanerThread(QThread):
    port_signal = Signal(list)
    def __init__(self):
        super().__init__()
        self.__running = True
        # self.ports = []
        # 微软语音
        # self.__spk = win32com.client.Dispatch("SAPI.SpVoice")
        # win10 消息提醒 API
        self.__toaster = ToastNotifier()
        self.__port_list = list('')
        self.__port_list_last = list('')
        self.__list2arr = []
        self.__list2arr_last = []
        self.__ico_path = os.path.dirname(os.path.abspath(__file__)) + "\\main.ico"
        self.__speak_en = False

        # 创建互斥锁避免多开
        mutex = win32event.CreateMutex(None, False, 'pomin serial toast tools')
        if win32api.GetLastError() > 0:
            self.__toaster.show_toast("串口插入监测已在运行",
                               "程序已经在运行~~~~~~~~~~~~~",
                               icon_path=self.__ico_path,
                               duration=5,
                               threaded=False
                               )
            self.stop()

    def run(self):
        print("进入扫描硬件进程")
        # self.my_tip("启动了，嗷~~~~", "串口插入监测开始运行")
        self.__port_list = list(serial.tools.list_ports.comports())
        self.__port_list_last = list(serial.tools.list_ports.comports())
        self.serial2arr()
        self.copy_arr(self.__list2arr, self.__list2arr_last)

        while self.__running :
            # QApplication.processEvents()
            self.copy_arr(self.__list2arr, self.__list2arr_last)
            self.copy_arr(self.__port_list, self.__port_list_last)
            self.__port_list = list(serial.tools.list_ports.comports())
            if len(self.__port_list) != 0:
                if len(self.__port_list) != len(self.__port_list_last):
                    self.port_signal.emit(self.__port_list)
                    if len(self.__port_list) > len(self.__port_list_last):
                        print('串口设备插入')
                        self.serial2arr()
                        for x in self.__list2arr:
                            if not self.is_in_arr(self.__list2arr_last, x):
                                print("add: " + str(self.__port_list[self.__list2arr.index(x)]))
                                # if self.__speak_en:
                                #     self.__spk.Speak(u"插入COM" + str(x))
                                # self.my_tip("串口设备插入", str(self.__port_list[self.__list2arr.index(x)]))
                                # print(self.__port_list[self.__list2arr.index(x)].name)
                                self.send_port_number_with_frame(self.__port_list[self.__list2arr.index(x)].name)
                    else:
                        print('串口设备拔出')
                        self.serial2arr()
                        for x in self.__list2arr_last:
                            if not self.is_in_arr(self.__list2arr, x):
                                print("remove: " + str(self.__port_list_last[self.__list2arr_last.index(x)]))
                                # if self.__speak_en:
                                #     self.__spk.Speak(u"拔出COM" + str(x))
                                # self.my_tip("串口设备拔出", str(self.__port_list_last[self.__list2arr_last.index(x)]))
                else:
                    QThread.msleep(500)

    def stop(self):
        self.__running = False
        self.__toaster = None
        print("退出扫描硬件进程")
        self.wait()

    '''
    win10 消息提醒
    '''

    def my_tip(self,title_="提示", msg_=""):
        self.__toaster.show_toast(
            title=title_, msg=msg_, icon_path=self.__ico_path, duration=3, threaded=True
        )

    '''
    一个数字是否在指定数组中
    '''

    def is_in_arr(self,arr, num):
        try:
            arr.index(num)
        except:
            return False
        return True

    '''
    拷贝数组、列表
    '''

    def copy_arr(self,arr1, arr2):
        arr2.clear()
        for xx in arr1:
            arr2.append(xx)

    '''
    刷新数组
    '''

    def serial2arr(self):
        self.__list2arr.clear()
        for i in range(0, len(self.__port_list)):
            if self.__port_list[i].name[:3] == 'COM':
                self.__list2arr.append(int(self.__port_list[i].name[3:]))

    def send_port_number_with_frame(self,port, baud_rate=115200):
        # 正则表达式匹配串口号中的数字
        match = re.search(r'\d+', port)
        if match:
            port_number = match.group()  # 提取数字部分
            # 将数字转换为十六进制，确保至少两位十六进制数
            port_number_hex = format(int(port_number), '02X').upper()
            try:
                # 打开串口
                with serial.Serial(port, baud_rate, timeout=1) as ser:
                    # 构造消息：帧头 + 数字串口号 + 帧尾
                    message = f"{'AA'}{port_number_hex}{'BB'}"
                    # 发送消息
                    ser.write(bytes.fromhex(message))
                    print(f"已发送 '{message}' 到 {port}")
            except serial.SerialException as e:
                print(f"无法打开串口 {port}: {e}")
            ser.close()
        else:
            print(f"无法从 {port} 提取数字串口号")
